home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 3.iso / dist / fw_qt3.idb / usr / freeware / Qt / extensions / nsplugin / src / qnp.cpp.z / qnp.cpp
C/C++ Source or Header  |  2002-04-08  |  50KB  |  2,022 lines

  1. /****************************************************************************
  2. ** $Id:  qt/qnp.cpp   3.0.3   edited Oct 12 12:18 $
  3. **
  4. ** Implementation of Qt extension classes for Netscape Plugin support.
  5. **
  6. ** Created : 970601
  7. **
  8. ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
  9. **
  10. ** This file is part of the Qt GUI Toolkit.
  11. **
  12. ** This file may be distributed under the terms of the Q Public License
  13. ** as defined by Trolltech AS of Norway and appearing in the file
  14. ** LICENSE.QPL included in the packaging of this file.
  15. **
  16. ** This file may be distributed and/or modified under the terms of the
  17. ** GNU General Public License version 2 as published by the Free Software
  18. ** Foundation and appearing in the file LICENSE.GPL included in the
  19. ** packaging of this file.
  20. **
  21. ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
  22. ** licenses may use this file in accordance with the Qt Commercial License
  23. ** Agreement provided with the Software.
  24. **
  25. ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
  26. ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  27. **
  28. ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
  29. **   information about Qt Commercial License Agreements.
  30. ** See http://www.trolltech.com/qpl/ for QPL licensing information.
  31. ** See http://www.trolltech.com/gpl/ for GPL licensing information.
  32. **
  33. ** Contact info@trolltech.com if any conditions of this licensing are
  34. ** not clear to you.
  35. **
  36. **********************************************************************/
  37.  
  38.  
  39. // Remaining Q_WS_X11 considerations:
  40. //   - What if !piApp upon NPP_NewStream?  Are we safe?
  41. //      - Yes, but users need to know of this:  that no GUI can be
  42. //         done until after setWindow is called.
  43. //   - Use NPN_GetValue in Communicator4.0 to get the display earlier!
  44. //   - For ClientMessage events, trap them, and if they are not for us,
  45. //    untrap them and retransmit them and set a timer to retrap them
  46. //    after N seconds.
  47.  
  48. // Remaining Q_WS_WIN considerations:
  49. //   - we need to activateZeroTimers() at some time.
  50. //   - we need to call winEventFilter on events
  51. //   - timers:
  52. //    if ( msg.message == WM_TIMER ) {            // timer message received
  53. //        activateTimer( msg.wParam );
  54. //        return TRUE;
  55. //    }
  56. //    if ( msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ) {
  57. //        if ( translateKeyCode(msg.wParam) == 0 ) {
  58. //            TranslateMessage( &msg );           // translate to WM_CHAR
  59. //            return TRUE;
  60. //        }
  61. //    }
  62. //   - qWinProcessConfigRequests?
  63.  
  64. // Remaining general stuff:
  65. //   - Provide the "reason" parameter to streamDestroyed
  66.  
  67. // Qt stuff
  68. #include <qapplication.h>
  69. #include <qwidget.h>
  70. #include <qobjectlist.h>
  71. #include <qcursor.h>
  72. #include <qprinter.h>
  73. #include <qfile.h>
  74. #include <qpainter.h>
  75.  
  76. #include "qnp.h"
  77.  
  78. #include <stdlib.h>        // Must be here for Borland C++
  79. #include <stdio.h>
  80. #include <string.h>
  81. #include <time.h>
  82. #include <limits.h>
  83.  
  84. #ifdef Q_WS_X11
  85. #define     GC GC_QQQ
  86. #endif
  87.  
  88. extern "C" {
  89. //
  90. // Netscape plugin API
  91. //
  92. #ifdef Q_WS_WIN
  93. #ifndef _WINDOWS
  94. #define _WINDOWS
  95. #endif
  96. #endif
  97. #ifdef Q_WS_X11
  98. #define XP_UNIX
  99. #endif
  100.  
  101. #include "npapi.h"
  102.  
  103. #ifdef Q_WS_X11
  104. #undef XP_UNIX
  105. #include "npunix.c"
  106. #endif
  107.  
  108. //
  109. // Stuff for the NPP_SetWindow function:
  110. //
  111. #ifdef Q_WS_X11
  112. #include <X11/Xlib.h>
  113. #include <X11/Intrinsic.h>
  114. #include <X11/IntrinsicP.h> // for XtCreateWindow
  115. #include <X11/Shell.h>
  116. #include <X11/StringDefs.h>
  117. #include <X11/Xutil.h>
  118. #include <X11/Xos.h>
  119. //#include <dlfcn.h>
  120. #endif
  121. #ifdef Q_WS_WIN
  122. #include <windows.h>
  123. #endif
  124. }
  125.  
  126. #ifdef Q_WS_WIN
  127. #include "npwin.cpp"
  128. #endif
  129.  
  130. struct _NPInstance
  131. {
  132.     NPWindow*        fWindow;
  133.     uint16            fMode;
  134.  
  135. #ifdef Q_WS_WIN
  136.     HWND            window;
  137.     WNDPROC            fDefaultWindowProc;
  138. #endif
  139.  
  140.     NPP npp;
  141.  
  142. #ifdef Q_WS_X11
  143.     Window window;
  144.     Display *display;
  145. #endif
  146.  
  147.     uint32 x, y;
  148.     uint32 width, height;
  149.  
  150.     QNPWidget* widget;
  151.     QNPInstance* instance;
  152.  
  153.     int16 argc;
  154.     QString *argn;
  155.     QString *argv;
  156. };
  157.  
  158.  
  159.  
  160. // The single global plugin
  161. static QNPlugin *qNP=0;
  162. static int instance_count=0;
  163.  
  164. // The single global application
  165. static class PluginSDK_QApplication *piApp=0;
  166.  
  167. // Temporary parameter passed `around the side' of calls to user functions
  168. static _NPInstance* next_pi=0;
  169.  
  170. // To avoid looping when browser OR plugin can delete streams
  171. static int qnps_no_call_back = 0;
  172.  
  173. // The currently in-focus widget.  This focus tracking is an auxiliary
  174. // service which we provide, since we know it anyway.
  175. static QNPWidget* focussedWidget=0;
  176.  
  177. #ifdef Q_WS_WIN
  178. // defined in qapplication_win.cpp
  179. Q_EXPORT extern bool qt_win_use_simple_timers;
  180. #endif
  181.  
  182. #ifdef Q_WS_X11
  183. static XtAppContext appcon;
  184.  
  185. typedef void (*SameAsXtTimerCallbackProc)(void*,void*);
  186. typedef void (*IntervalSetter)(int);
  187. typedef void (*ForeignEventProc)(XEvent*);
  188.  
  189. extern XtEventDispatchProc
  190.  qt_np_cascade_event_handler[LASTEvent];      // defined in qnpsupport.cpp
  191. void            qt_reset_color_avail();       // defined in qcolor_x11.cpp
  192. int             qt_activate_timers();         // defined in qapplication_x11.cpp
  193. timeval        *qt_wait_timer();              // defined in qapplication_x11.cpp
  194. void        qt_x11SendPostedEvents();     // defined in qapplication_x11.cpp
  195. Boolean  qt_event_handler( XEvent* event );   // defined in qnpsupport.cpp
  196. extern int      qt_np_count;                  // defined in qnpsupport.cpp
  197. void qt_np_timeout( void* p, void* id );      // defined in qnpsupport.cpp
  198. void qt_np_add_timeoutcb(
  199.     SameAsXtTimerCallbackProc cb );       // defined in qnpsupport.cpp
  200. void qt_np_remove_timeoutcb(
  201.     SameAsXtTimerCallbackProc cb );       // defined in qnpsupport.cpp
  202. void qt_np_add_timer_setter(
  203.     IntervalSetter is );                  // defined in qnpsupport.cpp
  204. void qt_np_remove_timer_setter(
  205.     IntervalSetter is );                  // defined in qnpsupport.cpp
  206. extern XtIntervalId qt_np_timerid;            // defined in qnpsupport.cpp
  207. extern bool qt_np_filters_installed[3];       // defined in qnpsupport.cpp
  208. extern void (*qt_np_leave_cb)
  209.           (XLeaveWindowEvent*);           // defined in qnpsupport.cpp
  210. void qt_np_add_event_proc(
  211.         ForeignEventProc fep );           // defined in qnpsupport.cpp
  212. void qt_np_remove_event_proc(
  213.         ForeignEventProc fep );           // defined in qnpsupport.cpp
  214.  
  215. enum FilterType { Safe, Dangerous, Blocked };
  216.  
  217. FilterType filterTypeFor(int event_type)
  218. {
  219.     switch (event_type) {
  220.       case KeymapNotify:
  221.       case Expose:
  222.       case GraphicsExpose:
  223.       case NoExpose:
  224.       case VisibilityNotify:
  225.       case PropertyNotify:
  226.       case SelectionClear:
  227.       case SelectionRequest:
  228.       case SelectionNotify:
  229.       case ColormapNotify:
  230.       case ClientMessage: // Hmm... is this safe?  I want the wm_deletes
  231.     return Safe;
  232.       default:
  233.     return Dangerous;
  234.     }
  235. }
  236.  
  237.  
  238. static
  239. void installXtEventFilters(FilterType t)
  240. {
  241.     if (qt_np_filters_installed[t]) return;
  242.     // Get Xt out of our face - install filter on every event type
  243.     for (int et=2; et < LASTEvent; et++) {
  244.     if ( filterTypeFor(et) == t )
  245.         qt_np_cascade_event_handler[et] = XtSetEventDispatcher(
  246.         qt_xdisplay(), et, qt_event_handler );
  247.     }
  248.     qt_np_filters_installed[t] = TRUE;
  249. }
  250.  
  251. static
  252. void removeXtEventFilters(FilterType t)
  253. {
  254.     if (!qt_np_filters_installed[t]) return;
  255.     // We aren't needed any more... slink back into the shadows.
  256.     for (int et=2; et < LASTEvent; et++) {
  257.     if ( filterTypeFor(et) == t )
  258.         XtSetEventDispatcher(
  259.         qt_xdisplay(), et, qt_np_cascade_event_handler[et] );
  260.     }
  261.     qt_np_filters_installed[t] = FALSE;
  262. }
  263.  
  264. // When we are in an event loop of QApplication rather than the browser's
  265. // event loop (eg. for a modal dialog), we still send repaint events to
  266. // the browser.
  267. static
  268. void np_event_proc( XEvent* e )
  269. {
  270.     Widget xtw = XtWindowToWidget( e->xany.display, e->xany.window );
  271.     if ( xtw && filterTypeFor( e->type ) == Safe ) {
  272.     // Graciously allow the browser to process the event
  273.     qt_np_cascade_event_handler[e->type]( e );
  274.     }
  275. }
  276.  
  277.  
  278. #endif
  279.  
  280. #ifdef Q_WS_WIN
  281. class PluginSDK_QApplication : public QApplication {
  282. #endif
  283.  
  284. #ifdef Q_WS_X11
  285. class PluginSDK_QApplication /* Not a QApplication */ {
  286. public:
  287.     PluginSDK_QApplication()
  288.     {
  289.     piApp = this;
  290.     }
  291.  
  292.     ~PluginSDK_QApplication()
  293.     {
  294.     piApp = 0;
  295.     }
  296.  
  297. #endif
  298.  
  299. #ifdef Q_WS_WIN
  300. private:
  301.     static int argc;
  302.     static char** argv;
  303.  
  304. public:
  305.     PluginSDK_QApplication() :
  306.     QApplication(argc, argv)
  307.     {
  308.     }
  309.  
  310.     void checkFocussedWidget()
  311.     {
  312.     POINT curPos;
  313.     if ( GetCursorPos( &curPos ) ) {
  314.         QPoint p(curPos.x, curPos.y);
  315.  
  316.         QNPWidget *newFocussedWidget = 0;
  317.         for ( QNPWidget* npw = npwidgets.first();
  318.         npw; npw = npwidgets.next() )
  319.         {
  320.         QRect r = npw->rect();
  321.         r.moveTopLeft( npw->mapToGlobal(QPoint(0,0)) );
  322.         if ( r.contains(p) ) {
  323.             newFocussedWidget = npw;
  324.             break;
  325.         }
  326.         }
  327.         if (newFocussedWidget != focussedWidget && focussedWidget)
  328.         focussedWidget->leaveInstance();
  329.  
  330.         if (newFocussedWidget) {
  331.         if (newFocussedWidget != focussedWidget)
  332.             newFocussedWidget->enterInstance();
  333.         }
  334.  
  335.         focussedWidget = newFocussedWidget;
  336.     }
  337.     }
  338.  
  339.     bool notify( QObject* obj, QEvent* event )
  340.     {
  341.     if ( event->type() == QEvent::Enter ||
  342.          event->type() == QEvent::Leave )
  343.     {
  344.         checkFocussedWidget();
  345.     }
  346.     return QApplication::notify( obj, event );
  347.     }
  348. #endif
  349.  
  350.     void addQNPWidget(QNPWidget* w)
  351.     {
  352.     npwidgets.append(w);
  353.     }
  354.  
  355.     void removeQNPWidget(QNPWidget* w)
  356.     {
  357.     if (w == focussedWidget) focussedWidget = 0;
  358.     npwidgets.remove(w);
  359.     }
  360.  
  361. #ifdef Q_WS_X11
  362.     static void removeXtEventFiltersIfOutsideQNPWidget(XLeaveWindowEvent* e)
  363.     {
  364.     // If QApplication doesn't know about the widget at the
  365.     // event point, we must should remove our filters.
  366.     // ### is widgetAt efficient enough?
  367.     QWidget* w = QApplication::widgetAt(e->x_root, e->y_root);
  368.  
  369.     if ( !w ) {
  370.         if ( focussedWidget ) {
  371.         focussedWidget->leaveInstance();
  372.         focussedWidget = 0;
  373.         }
  374.         removeXtEventFilters( Dangerous );
  375.     } else if ( w->isTopLevel() ) {
  376.         for ( QNPWidget* npw = npwidgets.first();
  377.         npw; npw = npwidgets.next())
  378.         {
  379.         if ( npw == w ) {
  380.             if ( focussedWidget != npw ) {
  381.             if ( focussedWidget ) {
  382.                 focussedWidget->leaveInstance();
  383.             }
  384.             focussedWidget = npw;
  385.             focussedWidget->enterInstance();
  386.             }
  387.  
  388.             break;
  389.         }
  390.         }
  391.     }
  392.     }
  393. #endif
  394.  
  395. private:
  396.     static QPtrList<QNPWidget> npwidgets;
  397. };
  398. QPtrList<QNPWidget> PluginSDK_QApplication::npwidgets;
  399.  
  400. #ifdef Q_WS_WIN
  401. int PluginSDK_QApplication::argc=0;
  402. char **PluginSDK_QApplication::argv={ 0 };
  403. #endif
  404.  
  405. #ifdef Q_WS_X11
  406. static void np_set_timer( int interval )
  407. {
  408.     // Ensure we only have one timeout in progress - QApplication is
  409.     // computing the one amount of time we need to wait.
  410.     if ( qt_np_timerid ) {
  411.     XtRemoveTimeOut( qt_np_timerid );
  412.     }
  413.     qt_np_timerid = XtAppAddTimeOut(appcon, interval,
  414.     (XtTimerCallbackProc)qt_np_timeout, 0);
  415.     /*
  416.     qt_np_timerid = XtAddTimeOut(interval,
  417.     (XtTimerCallbackProc)qt_np_timeout, 0);
  418.     */
  419. }
  420.  
  421. static void np_do_timers( void*, void* )
  422. {
  423.     qt_np_timerid = 0; // It's us, and we just expired, that's why we are here.
  424.  
  425.     qt_activate_timers();
  426.  
  427.     timeval *tm = qt_wait_timer();
  428.  
  429.     if (tm) {
  430.     int interval = QMIN(tm->tv_sec,INT_MAX/1000)*1000 + tm->tv_usec/1000;
  431.     np_set_timer( interval );
  432.     }
  433. }
  434. #endif
  435.  
  436.  
  437.  
  438. /******************************************************************************
  439.  * Plug-in Calls - these are called by Netscape
  440.  *****************************************************************************/
  441.  
  442.  
  443. // Instance state information about the plugin.
  444.  
  445. #ifdef Q_WS_X11
  446.  
  447. extern "C" char*
  448. NPP_GetMIMEDescription(void)
  449. {
  450.     if (!qNP) qNP = QNPlugin::create();
  451.     return (char*)qNP->getMIMEDescription();
  452. }
  453.  
  454.  
  455.  
  456. extern "C" NPError
  457. NPP_GetValue(void * /*future*/, NPPVariable variable, void *value)
  458. {
  459.     if (!qNP) qNP = QNPlugin::create();
  460.     NPError err = NPERR_NO_ERROR;
  461.     if (variable == NPPVpluginNameString)
  462.     *((const char **)value) = qNP->getPluginNameString();
  463.     else if (variable == NPPVpluginDescriptionString)
  464.     *((const char **)value) = qNP->getPluginDescriptionString();
  465.     else
  466.     err = NPERR_GENERIC_ERROR;
  467.  
  468.     return err;
  469. }
  470.  
  471. #endif
  472.  
  473. /*
  474. ** NPP_Initialize is called when your DLL is being loaded to do any
  475. ** DLL-specific initialization.
  476. */
  477. extern "C" NPError
  478. NPP_Initialize(void)
  479. {
  480. #ifdef Q_WS_WIN
  481.     qt_win_use_simple_timers = TRUE;
  482.     // Nothing more - we do it in DLLMain
  483. #endif
  484.  
  485.     if (!qNP) qNP = QNPlugin::create();
  486.     return NPERR_NO_ERROR;
  487. }
  488.  
  489. static jref plugin_java_class = 0;
  490.  
  491. /*
  492. ** NPP_GetJavaClass is called during initialization to ask your plugin
  493. ** what its associated Java class is. If you don't have one, just return
  494. ** NULL. Otherwise, use the javah-generated "use_" function to both
  495. ** initialize your class and return it. If you can't find your class, an
  496. ** error will be signalled by "use_" and will cause the Navigator to
  497. ** complain to the user.
  498. */
  499. extern "C" jref
  500. NPP_GetJavaClass(void)
  501. {
  502.     if (!qNP) qNP = QNPlugin::create();
  503.     plugin_java_class = (jref)qNP->getJavaClass();
  504.     return plugin_java_class;
  505. }
  506.  
  507. /*
  508. ** NPP_Shutdown is called when your DLL is being unloaded to do any
  509. ** DLL-specific shut-down. You should be a good citizen and declare that
  510. ** you're not using your java class any more. This allows java to unload
  511. ** it, freeing up memory.
  512. */
  513. extern "C" void
  514. NPP_Shutdown(void)
  515. {
  516.     if (qNP) {
  517.     if (plugin_java_class)
  518.         qNP->unuseJavaClass();
  519.     delete qNP;
  520.     qNP = 0;
  521.     }
  522.  
  523.     if (piApp) {
  524. #ifdef Q_WS_X11
  525.     qt_np_remove_timeoutcb(np_do_timers);
  526.     qt_np_remove_timer_setter(np_set_timer);
  527.     qt_np_remove_event_proc(np_event_proc);
  528.     qt_np_count--;
  529.  
  530.     if (qt_np_leave_cb == PluginSDK_QApplication::removeXtEventFiltersIfOutsideQNPWidget)
  531.         qt_np_leave_cb = 0;
  532.     if ( qt_np_count == 0) {
  533.         // We are the last Qt-based plugin to leave
  534.         removeXtEventFilters(Safe);
  535.         removeXtEventFilters(Dangerous);
  536.         if (qt_np_timerid) {
  537.         XtRemoveTimeOut( qt_np_timerid );
  538.         qt_np_timerid = 0;
  539.         }
  540.         qt_np_leave_cb = 0;
  541.     }
  542.     delete piApp;
  543. #endif
  544.     piApp = 0;
  545.  
  546.     delete qApp;
  547.     }
  548. }
  549.  
  550.  
  551. struct NS_Private {
  552.     uchar* a;
  553.     uchar* b;
  554. };
  555.  
  556. /*
  557. ** NPP_New is called when your plugin is instantiated (i.e. when an EMBED
  558. ** tag appears on a page).
  559. */
  560. extern "C" NPError
  561. NPP_New(NPMIMEType /*pluginType*/,
  562.     NPP instance,
  563.     uint16 mode,
  564.     int16 argc,
  565.     char* argn[],
  566.     char* argv[],
  567.     NPSavedData* /*saved*/)
  568. {
  569.     NPError result = NPERR_NO_ERROR;
  570.     _NPInstance* This;
  571.  
  572.     if (instance == NULL)
  573.     return NPERR_INVALID_INSTANCE_ERROR;
  574.  
  575.     instance->pdata = new _NPInstance;
  576.  
  577.     This = (_NPInstance*) instance->pdata;
  578.  
  579.     if (This == NULL)
  580.     return NPERR_OUT_OF_MEMORY_ERROR;
  581.  
  582.     This->npp = instance;
  583.  
  584.     /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */
  585.     This->fWindow = NULL;
  586.     This->fMode = mode;
  587.  
  588.     This->window = 0;
  589.  
  590. #ifdef Q_WS_WIN
  591.     This->fDefaultWindowProc = NULL;
  592. #endif
  593.  
  594.     This->widget = 0;
  595.  
  596.     This->argc = argc;
  597.     This->argn = new QString[argc+1];
  598.     This->argv = new QString[argc+1];
  599.     for (int i=0; i<This->argc; i++) {
  600.     This->argn[i] = argn[i];
  601.     This->argv[i] = argv[i];
  602.     }
  603.  
  604.     // Everything is set up - we can let QNPInstance be created now.
  605.     next_pi = This;
  606.     qNP->newInstance();
  607.     instance_count++;
  608.  
  609.     return result;
  610. }
  611.  
  612. extern "C" NPError
  613. NPP_Destroy(NPP instance, NPSavedData** /*save*/)
  614. {
  615.     _NPInstance* This;
  616.  
  617.     if (instance == NULL)
  618.     return NPERR_INVALID_INSTANCE_ERROR;
  619.  
  620.     This = (_NPInstance*) instance->pdata;
  621.  
  622.     if (This != NULL) {
  623. #ifdef Q_WS_WIN
  624.     SetWindowLong( This->window, GWL_WNDPROC,
  625.         (LONG)This->fDefaultWindowProc );
  626. #endif
  627.  
  628.     if (This->widget) {
  629.         This->widget->unsetWindow();
  630. #ifdef _WS_WIN_ // needed?
  631.         if (This->window)
  632.         NPP_SetWindow( instance, 0 ); // unset
  633. #endif
  634.         This->window = 0;
  635.         delete This->widget;
  636.     }
  637.  
  638.     delete This->instance;
  639.     delete [] This->argn;
  640.     delete [] This->argv;
  641.  
  642.     delete This;
  643.     instance->pdata = NULL;
  644.  
  645.     instance_count--;
  646.     }
  647.  
  648.     return NPERR_NO_ERROR;
  649. }
  650.  
  651.  
  652. extern "C" NPError
  653. NPP_SetWindow(NPP instance, NPWindow* window)
  654. {
  655.     if (!qNP) qNP = QNPlugin::create();
  656.     NPError result = NPERR_NO_ERROR;
  657.     _NPInstance* This;
  658.  
  659.     if (instance == NULL)
  660.     return NPERR_INVALID_INSTANCE_ERROR;
  661.  
  662.     This = (_NPInstance*) instance->pdata;
  663.  
  664.     if (!window) {
  665.  
  666.     if (This->widget) {
  667.         This->widget->unsetWindow();
  668.         This->window = 0;
  669.         delete This->widget;
  670.         This->widget = 0;
  671.     }
  672. #ifdef Q_WS_X11
  673.     } else if (This->window != (Window) window->window) {
  674.     This->window = (Window) window->window;
  675. #endif
  676. #ifdef Q_WS_WIN
  677.     } else if (This->window != (HWND) window->window) {
  678.     if (This->window)
  679.         SetWindowLong( This->window, GWL_WNDPROC,
  680.         (LONG)This->fDefaultWindowProc );
  681.     This->fDefaultWindowProc =
  682.         (WNDPROC)GetWindowLong( (HWND)window->window, GWL_WNDPROC);
  683.     This->window = (HWND) window->window;
  684. #endif
  685.     This->x = window->x;
  686.     This->y = window->y;
  687.     This->width = window->width;
  688.     This->height = window->height;
  689.  
  690. #ifdef Q_WS_X11
  691.     This->display =
  692.         ((NPSetWindowCallbackStruct *)window->ws_info)->display;
  693. #endif
  694.  
  695.     if (!piApp) {
  696. #ifdef Q_WS_X11
  697.         if (!qApp) {
  698.         // Thou Shalt Not Unload Qt
  699.         // Increment the reference count...
  700.         // dlopen("libqt.so.1", RTLD_LAZY);
  701.         // ... and never close it.
  702.         // Nice try.  Can't get that to work.
  703.  
  704.         // We are the first Qt-based plugin to arrive
  705.         new QApplication(This->display);
  706.  
  707.         // Helps debugging
  708.         //XSynchronize(This->display,True);
  709.         //XSetErrorHandler((int (*)(Display*dpy,XErrorEvent*))abort);
  710.  
  711.         ASSERT(qt_np_count == 0);
  712.         Q_ASSERT(qt_np_count == 0);
  713.         }
  714.         installXtEventFilters(Safe);
  715.         qt_np_add_timeoutcb(np_do_timers);
  716.         qt_np_add_timer_setter(np_set_timer);
  717.         qt_np_add_event_proc(np_event_proc);
  718.         qt_np_count++;
  719.         appcon = XtDisplayToApplicationContext(This->display);
  720. #endif
  721.         piApp = new PluginSDK_QApplication();
  722.     }
  723.  
  724.     if (!This->widget) {
  725. #ifdef Q_WS_WIN
  726.         This->window = (HWND) window->window;
  727.  
  728.         InvalidateRect( This->window, NULL, TRUE );
  729.         UpdateWindow( This->window );
  730. #endif
  731.         // New widget on this new window.
  732.         next_pi = This;
  733.         /* This->widget = */ // (happens sooner - in QNPWidget constructor)
  734.         This->instance->newWindow();
  735.         This->widget->show(); 
  736.     } else {
  737.         // New window for existing widget, and all its children.
  738.         This->widget->setWindow(FALSE);
  739.     }
  740.     } else if (This->widget) {
  741.     // ### Maybe need a geometry setter that bypasses some Qt code?
  742.     // ### position is always (0,0), so we get by by ignoring it.
  743.     if ( This->widget->width() != (int)window->width
  744.       || This->widget->height() != (int)window->height )
  745.     {
  746.         This->widget->setGeometry(window->x, window->y, window->width, window->height);
  747.     } else {
  748.         This->widget->update();
  749.     }
  750.     }
  751.  
  752.     This->fWindow = window;
  753.     return result;
  754. }
  755.  
  756.  
  757. extern "C" NPError
  758. NPP_NewStream(NPP instance,
  759.       NPMIMEType type,
  760.       NPStream *stream,
  761.       NPBool seekable,
  762.       uint16 *stype)
  763. {
  764.     _NPInstance* This;
  765.  
  766.     if (instance == NULL)
  767.     return NPERR_INVALID_INSTANCE_ERROR;
  768.  
  769.     This = (_NPInstance*) instance->pdata;
  770.  
  771.     if ( This ) {
  772.     QNPStream* qnps = new QNPStream(This->instance,type,stream,seekable);
  773.     stream->pdata = qnps;
  774.     QNPInstance::StreamMode sm = (QNPInstance::StreamMode)*stype;
  775.     if (!This->instance->newStreamCreated(qnps, sm)) {
  776.         return NPERR_GENERIC_ERROR;
  777.     }
  778.     *stype = sm;
  779.     }
  780.  
  781.     return NPERR_NO_ERROR;
  782. }
  783.  
  784.  
  785. int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
  786.                    * mode so we can take any size stream in our
  787.                    * write call (since we ignore it) */
  788.  
  789. extern "C" int32
  790. NPP_WriteReady(NPP instance, NPStream *stream)
  791. {
  792.     _NPInstance* This;
  793.     if (instance != NULL) {
  794.     This = (_NPInstance*) instance->pdata;
  795.     } else {
  796.     // Yikes, that's unusual!
  797.     return 0;
  798.     }
  799.  
  800.     if (This) {
  801.     return This->instance->writeReady((QNPStream*)stream->pdata);
  802.     }
  803.  
  804.     /* Number of bytes ready to accept in NPP_Write() */
  805.     return STREAMBUFSIZE;
  806. }
  807.  
  808.  
  809. extern "C" int32
  810. NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
  811. {
  812.     if (instance != NULL)
  813.     {
  814.     _NPInstance* This = (_NPInstance*) instance->pdata;
  815.  
  816.     if (This) {
  817.         return This->instance->write((QNPStream*)stream->pdata,
  818.         offset, len, buffer);
  819.     }
  820.     }
  821.  
  822.     return len;        /* The number of bytes accepted */
  823. }
  824.  
  825.  
  826. extern "C" NPError
  827. NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
  828. {
  829.     _NPInstance* This;
  830.  
  831.     if (instance == NULL)
  832.     return NPERR_INVALID_INSTANCE_ERROR;
  833.  
  834.     if (!qnps_no_call_back) {
  835.     This = (_NPInstance*) instance->pdata;
  836.  
  837.     QNPStream* qnps = (QNPStream*)stream->pdata;
  838.     switch (reason) {
  839.       case NPRES_DONE:
  840.         qnps->setComplete(TRUE);
  841.         break;
  842.       case NPRES_USER_BREAK:
  843.         break;
  844.       case NPRES_NETWORK_ERR:
  845.         qnps->setOkay(FALSE);
  846.         break;
  847.     }
  848.  
  849.     if (This) {
  850.         // Give the instance a chance to do something
  851.         This->instance->streamDestroyed(qnps);
  852.     }
  853.  
  854.     qnps_no_call_back++;
  855.     delete qnps;
  856.     qnps_no_call_back--;
  857.     }
  858.  
  859.     return NPERR_NO_ERROR;
  860. }
  861.  
  862.  
  863. extern "C" void
  864. NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
  865. {
  866.     _NPInstance* This;
  867.  
  868.     if (instance == NULL) return;
  869.  
  870.     This = (_NPInstance*) instance->pdata;
  871.  
  872.     if ( This ) {
  873.     QNPStream* qnps = (QNPStream*)stream->pdata;
  874.     This->instance->streamAsFile(qnps, fname);
  875.     }
  876. }
  877.  
  878. typedef struct
  879. {
  880.     int32    type;
  881.     FILE*    fp;
  882. } NPPrintCallbackStruct;
  883.  
  884. #ifdef Q_WS_X11
  885.  
  886. class QNPPrinter : public QPrinter {
  887.     QFile file;
  888. public:
  889.     QNPPrinter(FILE* fp)
  890.     {
  891.     file.open(IO_WriteOnly, fp);
  892.     QPDevCmdParam param;
  893.     param.device = &file;
  894.     cmd(PdcSetdev, 0, ¶m);
  895.     }
  896.     void end()
  897.     {
  898.     QPDevCmdParam param;
  899.     param.device = 0;
  900.     cmd(PdcSetdev, 0, ¶m);
  901.     }
  902. };
  903. #endif
  904.  
  905. extern "C" void
  906. NPP_Print(NPP instance, NPPrint* printInfo)
  907. {
  908.     if(printInfo == NULL)
  909.     return;
  910.  
  911.     if (instance != NULL) {
  912.     _NPInstance* This = (_NPInstance*) instance->pdata;
  913.  
  914.     if (printInfo->mode == NP_FULL) {
  915.         printInfo->print.fullPrint.pluginPrinted =
  916.         This->instance->printFullPage();
  917.     } else if (printInfo->mode == NP_EMBED) {
  918. #ifdef Q_WS_X11
  919.         void* platformPrint =
  920.         printInfo->print.embedPrint.platformPrint;
  921.         FILE* outfile = ((NPPrintCallbackStruct*)platformPrint)->fp;
  922.         if (ftell(outfile)) {
  923.         NPWindow* w =
  924.             &(printInfo->print.embedPrint.window);
  925.         QNPPrinter prn(outfile);
  926.         QPainter painter(&prn);
  927.         // #### config viewport with w->{x,y,width,height}
  928.         This->instance->print(&painter);
  929.         prn.end();
  930.         } else {
  931.         // Why does the browser make spurious NPP_Print calls?
  932.         }
  933. #endif
  934. #ifdef Q_WS_WIN
  935.         NPWindow* printWindow =
  936.         &(printInfo->print.embedPrint.window);
  937.         void* platformPrint =
  938.         printInfo->print.embedPrint.platformPrint;
  939.         // #### Nothing yet.
  940. #endif
  941.     }
  942.     }
  943. }
  944.  
  945. extern "C" void
  946. NPP_URLNotify(NPP instance,
  947.           const char* url,
  948.           NPReason reason,
  949.           void* notifyData)
  950. {
  951.     if (instance != NULL) {
  952.     QNPInstance::Reason r;
  953.     switch (reason) {
  954.     case NPRES_DONE:
  955.         r = QNPInstance::ReasonDone;
  956.         break;
  957.     case NPRES_USER_BREAK:
  958.         r = QNPInstance::ReasonBreak;
  959.         break;
  960.     case NPRES_NETWORK_ERR:
  961.         r = QNPInstance::ReasonError;
  962.         break;
  963.     default:
  964.         r = QNPInstance::ReasonUnknown;
  965.         break;
  966.     }
  967.     _NPInstance* This = (_NPInstance*) instance->pdata;
  968.     This->instance->notifyURL(url, r, notifyData);
  969.     }
  970. }
  971.  
  972.  
  973.  
  974. // Hackery for X11:  make Qt's toplevels widgets be Xt widgets too.
  975.  
  976. #ifdef Q_WS_X11
  977.  
  978. // Called when a top-level widget (which has an Xt widget's window) is entered.
  979. static
  980. void enter_event_handler(Widget, XtPointer xtp, XEvent* event, Boolean* cont)
  981. {
  982.     _NPInstance* This = (_NPInstance*)xtp;
  983.  
  984.     if (piApp) {
  985.     installXtEventFilters(Dangerous);
  986.     if ( xtp ) {
  987.         if ( focussedWidget )
  988.         focussedWidget->leaveInstance();
  989.  
  990.         focussedWidget = This->widget;
  991.  
  992.         if ( focussedWidget ) {
  993.         focussedWidget->enterInstance();
  994.         qt_np_leave_cb = PluginSDK_QApplication::removeXtEventFiltersIfOutsideQNPWidget;
  995.         }
  996.     }
  997.     // Post the event
  998.     *cont = qt_event_handler(event);
  999.     } else {
  1000.     *cont = FALSE;
  1001.     }
  1002. }
  1003.  
  1004. // Called when a top-level widget (which has an Xt widget's window) is left.
  1005. static
  1006. void leave_event_handler(Widget, XtPointer, XEvent*, Boolean* cont)
  1007. {
  1008.     if (piApp) {
  1009.     if ( !QApplication::activePopupWidget()
  1010.       && !QApplication::activeModalWidget() )
  1011.     {
  1012.         if ( focussedWidget ) {
  1013.         focussedWidget->leaveInstance();
  1014.         focussedWidget = 0;
  1015.         }
  1016.         removeXtEventFilters(Dangerous);
  1017.     }
  1018.     }
  1019.     *cont = FALSE;
  1020. }
  1021.  
  1022. // Relacement for Qt function - add Xt stuff for top-level widgets
  1023. Window qt_XCreateWindow( const QWidget* qw, Display *display, Window parent,
  1024.              int x, int y, uint w, uint h,
  1025.              int borderwidth, int depth,
  1026.              uint windowclass, Visual *visual,
  1027.              ulong valuemask, XSetWindowAttributes *attributes )
  1028. {
  1029.     // ### This isA will not work - we are still in QWidget's constructor.
  1030.     if ( qw->isTopLevel() && !qw->isA("QNPWidget") ) {
  1031.     // ### not sure it is good to use name() and className().
  1032.     bool cmap = valuemask & CWColormap;
  1033.     Widget xtw = XtVaAppCreateShell( qw->name(), qw->className(),
  1034.         applicationShellWidgetClass, display,
  1035.         XtNx, x, XtNy, y, XtNwidth, w, XtNheight, h,
  1036.         XtNborderWidth, borderwidth, XtNdepth, depth,
  1037.         XtNvisual, visual,
  1038.         cmap ? XtNcolormap : 0, cmap ? attributes->colormap : 0,
  1039.         0, 0 );
  1040.  
  1041.     // Ensure it has a window, and get it.
  1042.     XtSetMappedWhenManaged( xtw, FALSE );
  1043.     XtRealizeWidget( xtw );
  1044.     Window xw = XtWindow( xtw );
  1045.  
  1046.     // Set the attributes (directly)
  1047.     XChangeWindowAttributes( display, xw, valuemask, attributes );
  1048.  
  1049.     // Inform us on enter/leave
  1050.     XtAddEventHandler( xtw, EnterWindowMask, TRUE, enter_event_handler, 0 );
  1051.     XtAddEventHandler( xtw, LeaveWindowMask, TRUE, leave_event_handler, 0 );
  1052.  
  1053.     // Return Xt's window for the widget
  1054.     return xw;
  1055.     } else {
  1056.     Window window = XCreateWindow( display, parent, x, y, w, h, borderwidth, depth,
  1057.                   windowclass, visual, valuemask, attributes );
  1058.     return window;
  1059.     }
  1060. }
  1061.  
  1062.  
  1063. // Relacement for Qt function - add Xt stuff for top-level widgets
  1064. Window qt_XCreateSimpleWindow( const QWidget* qw, Display *display, Window parent,
  1065.                    int x, int y, uint w, uint h, int borderwidth,
  1066.                    ulong border, ulong background )
  1067. {
  1068.     // ### This isA will not work - we are still in QWidget's constructor.
  1069.     Window window;
  1070.     if ( qw->isTopLevel() && !qw->isA("QNPWidget") ) {
  1071.     XSetWindowAttributes attributes;
  1072.     attributes.border_pixel = border;
  1073.     attributes.background_pixel = background;
  1074.     window = qt_XCreateWindow (
  1075.         qw, display, parent, x, y, w, h, borderwidth,
  1076.         CopyFromParent, CopyFromParent, CopyFromParent,
  1077.         CWBackPixel | CWBorderPixel, &attributes );
  1078.     } else {
  1079.     window = XCreateSimpleWindow( display, parent, x, y, w, h, borderwidth,
  1080.                     border, background );
  1081.     }
  1082.     return window;
  1083. }
  1084.  
  1085.  
  1086. // Relacement for Qt function - add Xt stuff for top-level widgets
  1087. void qt_XDestroyWindow( const QWidget* qw, Display *display, Window window )
  1088. {
  1089.  
  1090.     if ( qw->isTopLevel() && !qw->isA("QNPWidget") ) {
  1091.     Widget xtw = XtWindowToWidget( display, window );
  1092.     if ( xtw ) {
  1093.         XtRemoveEventHandler(xtw, LeaveWindowMask, TRUE, leave_event_handler, 0);
  1094.         XtRemoveEventHandler(xtw, EnterWindowMask, TRUE, enter_event_handler, 0);
  1095.         XtDestroyWidget( xtw );
  1096.     } else {
  1097.         XDestroyWindow( display, window );
  1098.     }
  1099.     } else {
  1100.     XDestroyWindow( display, window );
  1101.     }
  1102. }
  1103.  
  1104. #endif
  1105.  
  1106.  
  1107.  
  1108. #ifdef Q_WS_WIN
  1109.  
  1110. BOOL   WINAPI   DllMain (HANDLE hInst,
  1111.             ULONG ul_reason_for_call,
  1112.             LPVOID lpReserved)
  1113. {
  1114.     switch ( ul_reason_for_call ) {
  1115.     case DLL_PROCESS_ATTACH:
  1116.     case DLL_THREAD_ATTACH:
  1117.         WinMain( (HINSTANCE)hInst, 0, "", SW_SHOW );
  1118.         break;
  1119.     case DLL_PROCESS_DETACH:
  1120.     case DLL_THREAD_DETACH:
  1121.         break;
  1122.     }
  1123.  
  1124.     return TRUE;
  1125. }
  1126.  
  1127. int main(int argc, char** argv)
  1128. {
  1129.     return 0;
  1130. }
  1131.  
  1132. #endif
  1133.  
  1134.  
  1135.  
  1136. /*!
  1137.   \class QNPWidget qnp.h
  1138.   \brief The QNPWidget class provides a QWidget that is a Web-browser plugin window.
  1139.  
  1140.   \extension NSPlugin
  1141.  
  1142.   Derive from QNPWidget to create a widget that can be used as a
  1143.   Browser plugin window, or create one and add child widgets.
  1144.   Instances of QNPWidget may only be created
  1145.   when QNPInstance::newWindow() is called by the browser.
  1146.  
  1147.   A common way to develop a plugin widget is to develop it as a stand-alone
  1148.   application window, then make it a \e child of a plugin widget to use
  1149.   it as a browser plugin.  The technique is:
  1150.  
  1151. \code
  1152. class MyPluginWindow : public QNPWidget {
  1153.     QWidget* child;
  1154. public:
  1155.     MyPluginWindow()
  1156.     {
  1157.     // Some widget that is normally used as a top-level widget
  1158.     child = new MyIndependentlyDevelopedWidget();
  1159.  
  1160.     // Use the background color of the web page
  1161.     child->setBackgroundColor( backgroundColor() );
  1162.  
  1163.     // Fill the plugin widget
  1164.     child->setGeometry( 0, 0, width(), height() );
  1165.     }
  1166.  
  1167.     void resizeEvent(QResizeEvent*)
  1168.     {
  1169.     // Fill the plugin widget
  1170.     child->resize(size());
  1171.     }
  1172. };
  1173. \endcode
  1174.  
  1175.   The default implementation is an empty window.
  1176. */
  1177.  
  1178. /*!
  1179.   Creates a QNPWidget.
  1180. */
  1181. QNPWidget::QNPWidget() :
  1182.     pi(next_pi)
  1183. {
  1184.     if (!next_pi) {
  1185.     qFatal("QNPWidget must only be created within call to newWindow");
  1186.     }
  1187.     next_pi->widget = this;
  1188.     next_pi = 0;
  1189.  
  1190.     setWindow(TRUE);
  1191.  
  1192.     piApp->addQNPWidget(this);
  1193.  
  1194. #ifdef Q_WS_WIN
  1195.     // Communicator and explorer give us an unshown
  1196.     // widget.  Navigator gives us a shown one.
  1197.     QWidget::show();
  1198. #endif
  1199. }
  1200.  
  1201. /*!
  1202.   Destroys the window.  This will be called by the plugin binding code
  1203.   when the window is no longer required.  The Web-browser will delete windows
  1204.   when they leave the page.  The bindings will change the QWidget::winId()
  1205.   of the window when the window is resized, but this should not affect
  1206.   normal widget behavior.
  1207. */
  1208. QNPWidget::~QNPWidget()
  1209. {
  1210.     piApp->removeQNPWidget(this);
  1211. }
  1212.  
  1213. /*!
  1214.   Called when the mouse enters the plugin window.  Does nothing by
  1215.   default.
  1216. */
  1217. void QNPWidget::enterInstance()
  1218. {
  1219. }
  1220.  
  1221. /*!
  1222.   Called when the mouse leaves the plugin window.  Does nothing by
  1223.   default.
  1224. */
  1225. void QNPWidget::leaveInstance()
  1226. {
  1227. }
  1228.  
  1229. /*!
  1230.   Returns the instance for which this widget is the window.
  1231. */
  1232. QNPInstance* QNPWidget::instance()
  1233. {
  1234.     return pi->instance;
  1235. }
  1236.  
  1237. class QFixableWidget : public QWidget {
  1238. public:
  1239.     void fix()
  1240.     {
  1241.     QRect g = geometry();
  1242.     QColor bg = backgroundColor();
  1243.     bool mt = hasMouseTracking();
  1244.     bool hascurs = testWFlags( WState_OwnCursor );
  1245.     QCursor curs = cursor();
  1246.     clearWState( WState_Created );
  1247.     clearWState( WState_Visible );
  1248.     create( 0, TRUE, FALSE );
  1249.     setGeometry(g);
  1250.     setBackgroundColor( bg );
  1251.     setMouseTracking( mt );
  1252.     if ( hascurs ) {
  1253.         setCursor( curs );
  1254.     }
  1255.     }
  1256. };
  1257.  
  1258. static
  1259. void createNewWindowsForAllChildren(QWidget* parent, int indent=0)
  1260. {
  1261.     QObjectList* list = parent->queryList("QWidget", 0, FALSE, FALSE);
  1262.  
  1263.     if ( list ) {
  1264.     QObjectListIt it( *list );
  1265.     QFixableWidget* c;
  1266.     while ( (c = (QFixableWidget*)it.current()) ) {
  1267.         bool vis = c->isVisible();
  1268.         // Fix children first, so propagation can work
  1269.         createNewWindowsForAllChildren(c,indent+1);
  1270.         c->fix();
  1271.         if ( vis ) 
  1272.         c->show(); // Now that all children are valid.                
  1273.         ++it;
  1274.     }
  1275.     delete list;
  1276.     }
  1277. }
  1278.  
  1279. /*!
  1280.     \internal
  1281.   For internal use only.
  1282.   If \a delold parameter is passed to the create() function.
  1283. */
  1284. void QNPWidget::setWindow(bool delold)
  1285. {
  1286.     saveWId = winId(); // ### Don't need this anymore
  1287.  
  1288.     create((WId)pi->window, FALSE, delold);
  1289.  
  1290.    if ( delold ) {
  1291.       // Make sure they get a show()
  1292.       clearWState( WState_Visible );
  1293.    }
  1294.  
  1295. #ifdef Q_WS_X11
  1296.     Widget w = XtWindowToWidget (qt_xdisplay(), pi->window);
  1297.     XtAddEventHandler(w, EnterWindowMask, FALSE, enter_event_handler, pi);
  1298.     XtAddEventHandler(w, LeaveWindowMask, FALSE, leave_event_handler, pi);
  1299.     Pixmap bgpm=0;
  1300.     XColor col;
  1301.     XtVaGetValues(w,
  1302.     XtNbackground, &col.pixel,
  1303.     XtNbackgroundPixmap, &bgpm,
  1304.     0, 0);
  1305.     XQueryColor(qt_xdisplay(), x11Colormap(), &col);
  1306.     setBackgroundColor(QColor(col.red >> 8, col.green >> 8, col.blue >> 8));
  1307.     if (bgpm) {
  1308.     // ### Need an under-the-hood function here, or we have to
  1309.     // ### rewrite lots of code from QPixmap::convertToImage().
  1310.     // ### Doesn't matter yet, because Netscape doesn't ever set
  1311.     // ### the background image of the window it gives us.
  1312.     }
  1313. #endif
  1314.  
  1315.     createNewWindowsForAllChildren(this);
  1316.  
  1317.     setGeometry( pi->x, pi->y, pi->width, pi->height );
  1318. }
  1319.  
  1320. /*!
  1321.   For internal use only.
  1322.   \internal
  1323. */
  1324. void QNPWidget::unsetWindow()
  1325. {
  1326. #ifdef Q_WS_X11
  1327.     WId wi = winId();
  1328.     Widget w = XtWindowToWidget (qt_xdisplay(), wi);
  1329.     if ( w ) {
  1330.     XtRemoveEventHandler(w, LeaveWindowMask, FALSE, leave_event_handler, pi);
  1331.     XtRemoveEventHandler(w, EnterWindowMask, FALSE, enter_event_handler, pi);
  1332.     }
  1333.     destroy( FALSE, FALSE ); // Xt has already destroyed all the windows
  1334. #endif
  1335. #ifdef Q_WS_WIN
  1336.     // Nothing special
  1337.     destroy( FALSE, TRUE ); // Browser will the window, but not the subwindows
  1338. #endif
  1339. }
  1340.  
  1341.  
  1342.  
  1343. /*!
  1344.   \class QNPInstance qnp.h
  1345.   \brief The QNPInstance class provides a QObject that is a Web-browser plugin.
  1346.  
  1347.   \extension NSPlugin
  1348.  
  1349.   Deriving from QNPInstance creates an object that represents a single
  1350.   \c{<EMBED>} tag in an HTML document.
  1351.  
  1352.   The QNPInstance is responsible for creating an appropriate window if
  1353.   required (not all plugins have windows), and for interacting with the
  1354.   input/output facilities intrinsic to plugins.
  1355.  
  1356.   Note that there is \e{absolutely no guarantee} regarding the order in
  1357.   which functions are called.  Sometimes the browser will call newWindow()
  1358.   first, at other times, newStreamCreated() will be called first (assuming the
  1359.   \c{<EMBED>} tag has a SRC parameter).
  1360.  
  1361.   \e{None of Qt's GUI functionality} may be used until after the first call
  1362.   to newWindow().  This includes any use of QPaintDevice (ie. QPixmap,
  1363.   QWidget, and all subclasses), QApplication, anything related to
  1364.   QPainter (QBrush, etc.), fonts, QMovie, QToolTip, etc.  Useful
  1365.   classes which specifically \e can be used are QImage, QFile,
  1366.   and QBuffer.
  1367.  
  1368.   By structuring your plugin so that
  1369.   the task of the QNPInstance is to gather data, while
  1370.   the task of the QNPWidget is to provide a graphical interface to that data,
  1371.   this restriction can easily be accommodated.
  1372. */
  1373.  
  1374. /*! \enum QNPInstance::InstanceMode
  1375.  
  1376.   This enum type provides Qt-style names for three #defines in
  1377.   npapi.h:
  1378.  
  1379.   \value Embed - corresponds to NP_EMBED
  1380.   \value Full - corresponds to NP_FULL
  1381.   \value Background - corresponds to NP_BACKGROUND
  1382.  
  1383. */
  1384. /*! \enum QNPInstance::Reason
  1385.  
  1386.     \value ReasonDone
  1387.     \value ReasonBreak
  1388.     \value ReasonError
  1389.     \value ReasonUnknown
  1390. */
  1391. /*! \enum QNPInstance::StreamMode
  1392.     \value Normal
  1393.     \value Seek
  1394.     \value AsFile
  1395.     \value AsFileOnly
  1396. */
  1397.  
  1398. /*!
  1399.   Creates a QNPInstance.
  1400.   Can only be called from within a derived class created
  1401.   within QNPlugin::newInstance().
  1402. */
  1403. QNPInstance::QNPInstance() :
  1404.     pi(next_pi)
  1405. {
  1406.     if (!next_pi) {
  1407.     qFatal("QNPInstance must only be created within call to newInstance");
  1408.     }
  1409.     next_pi->instance = this;
  1410.     next_pi = 0;
  1411. }
  1412.  
  1413. /*!
  1414.   Called when the plugin instance is about to disappear.
  1415. */
  1416. QNPInstance::~QNPInstance()
  1417. {
  1418. }
  1419.  
  1420. /*!
  1421.   Called at most once, at some time after the QNPInstance is created.
  1422.   If the plugin requires a window, this function should return a derived
  1423.   class of QNPWidget that provides the required interface.
  1424. */
  1425. QNPWidget* QNPInstance::newWindow()
  1426. {
  1427.     // No window by default
  1428.     next_pi = 0;
  1429.     return 0;
  1430. }
  1431.  
  1432. /*!
  1433.   Returns the plugin window created by newWindow(), if any.
  1434. */
  1435. QNPWidget* QNPInstance::widget()
  1436. {
  1437.     return pi->widget;
  1438. }
  1439.  
  1440. /*!
  1441.   \fn bool QNPInstance::newStreamCreated(QNPStream*, StreamMode& smode)
  1442.  
  1443.   This function is called when a new stream has been created.
  1444.   The instance should return TRUE if it accepts the processing
  1445.   of the stream.  If the instance requires the stream as a file,
  1446.   it should set \a smode to AsFileOnly, in which case the data
  1447.   will be delivered some time later to the streamAsFile() function.
  1448.   Otherwise, the data will be delivered in chunks to the write()
  1449.   function which must consume at least as much data as was returned
  1450.   by the most recent call to writeReady().
  1451.  
  1452.   Note that the AsFileOnly method is not supported by Netscape 2.0
  1453.   and MSIE 3.0.
  1454.  
  1455. */
  1456. bool QNPInstance::newStreamCreated(QNPStream*, StreamMode&)
  1457. {
  1458.     return FALSE;
  1459. }
  1460.  
  1461. /*!
  1462.   Called when a stream is delivered as a single file called \a fname
  1463.   rather than as chunks.  This may be simpler for a plugin to deal
  1464.   with, but precludes any incremental behavior.
  1465.  
  1466.   Note that the AsFileOnly method is not supported by Netscape 2.0
  1467.   and MSIE 3.0.
  1468.  
  1469.   \sa newStreamCreated(), newStream()
  1470. */
  1471. void QNPInstance::streamAsFile(QNPStream*, const char*)
  1472. {
  1473. }
  1474.  
  1475. /*!
  1476.   Called when a stream is destroyed.  At this point, the stream may
  1477.   be complete() and okay().  If it is not okay(), then an error has
  1478.   occurred.  If it is okay(), but not complete(), then the user has
  1479.   cancelled the transmission - do not give an error message in this case.
  1480. */
  1481. void QNPInstance::streamDestroyed(QNPStream*)
  1482. {
  1483. }
  1484.  
  1485. /*!
  1486.     Returns the minimum amount of data the instance is
  1487.   willing to receive from the given stream.
  1488.  
  1489.   The default returns a very large value.
  1490. */
  1491. int QNPInstance::writeReady(QNPStream*)
  1492. {
  1493.     // Yes, we can handle any amount of data at once.
  1494.     return 0X0FFFFFFF;
  1495. }
  1496.  
  1497. /*!
  1498.   \fn int QNPInstance::write(QNPStream*, int offset, int len, void* buffer)
  1499.  
  1500.   Called when incoming data is available for processing by the instance.
  1501.   The instance \e must consume at least the amount that it returned in
  1502.   the most recent call to writeReady(), but it may consume up to the
  1503.   amount given by \a len.  \a buffer is the data available for consumption.
  1504.   The \a offset argument is merely an informational
  1505.   value indicating the total amount of data that has been consumed
  1506.   in prior calls.
  1507.  
  1508.   This function should return the amount of data actually consumed.
  1509. */
  1510. int QNPInstance::write(QNPStream*, int, int len, void*)
  1511. {
  1512.     // Yes, we processed it all... into the bit bucket.
  1513.     return len;
  1514. }
  1515.  
  1516. /*!
  1517.   Requests that the \a url be retrieved and sent to the named
  1518.   \a window.  See Netscape's JavaScript documentation for an explanation
  1519.   of window names.
  1520. */
  1521. void QNPInstance::getURL(const char* url, const char* window)
  1522. {
  1523.     NPN_GetURL( pi->npp, url, window );
  1524. }
  1525.  
  1526. /*!
  1527.     \preliminary
  1528.   This function is \e{not tested}.
  1529.  
  1530.   It is an interface to the NPN_PostURL function of the Netscape
  1531.   Plugin API.
  1532.  
  1533.   Passes \a url, \a window, \a buf, \a len, and \a file to
  1534.   NPN_PostURL.
  1535. */
  1536. void QNPInstance::postURL(const char* url, const char* window,
  1537.          uint len, const char* buf, bool file)
  1538. {
  1539.     NPN_PostURL( pi->npp, url, window, len, buf, file );
  1540. }
  1541.  
  1542. /*!
  1543.   Print the instance full-page.  By default, this returns FALSE, causing the
  1544.   browser to call the (embedded) print() function instead.
  1545.   Requests that the given \a url be retrieved and sent to the named
  1546.   \a window.  See Netscape's JavaScript documentation for an explanation
  1547.   of window names. Passes the arguments including \a data to
  1548.   NPN_GetURLNotify.
  1549.  
  1550.   \sa
  1551.   \link http://developer.netscape.com/docs/manuals/communicator/plugin/refpgur.htm#npngeturlnotify
  1552.   Netscape: NPN_GetURLNotify method\endlink
  1553. */
  1554. void QNPInstance::getURLNotify(const char* url, const char* window, void*data)
  1555. {
  1556. #ifdef Q_WS_WIN // Only on Windows?
  1557.     NPN_GetURLNotify( pi->npp, url, window, data );
  1558. #endif
  1559. }
  1560.  
  1561. /*!
  1562.     \preliminary
  1563.   This function is \e{not tested}.
  1564.   It is an encapsulation of the NPP_Print
  1565.   function of the Netscape Plugin API.
  1566. */
  1567. bool QNPInstance::printFullPage()
  1568. {
  1569.     return FALSE;
  1570. }
  1571.  
  1572. /*!
  1573.     \preliminary
  1574.   This function is \e{not tested}.
  1575.  
  1576.   Print the instance embedded in a page.
  1577.  
  1578.   It is an encapsulation of the NPP_Print
  1579.   function of the Netscape Plugin API.
  1580. */
  1581. void QNPInstance::print(QPainter*)
  1582. {
  1583.     // ### default could redirected-print the window.
  1584. }
  1585.  
  1586. /*!
  1587.   Returns the number of arguments to the instance.  Note that you should
  1588.   not normally rely on the ordering of arguments, and also note that
  1589.   the SGML specification does not permit multiple arguments with the same
  1590.   name.
  1591.  
  1592.   \sa arg()
  1593. */
  1594. int QNPInstance::argc() const
  1595. {
  1596.     return pi->argc;
  1597. }
  1598.  
  1599. /*!
  1600.   Returns the name of the \a{i}-th argument.  See argc().
  1601. */
  1602. const char* QNPInstance::argn(int i) const
  1603. {
  1604.     return pi->argn[i];
  1605. }
  1606.  
  1607. /*!
  1608.     \preliminary
  1609.   This function is \e{not tested}.
  1610.  
  1611.   Called whenever a \a url is notified after call to NPN_GetURLNotify
  1612.   with \a notifyData. The reason is given in \a r.
  1613.  
  1614.   It is an encapsulation of the NPP_URLNotify
  1615.   function of the Netscape Plugin API.
  1616.  
  1617.   See also:
  1618.   \link http://developer.netscape.com/docs/manuals/communicator/plugin/refpgur.htm#nppurlnotify
  1619.   Netscape: NPP_URLNotify method\endlink
  1620. */
  1621. void QNPInstance::notifyURL(const char*, Reason, void*)
  1622. {
  1623. }
  1624.  
  1625. /*!
  1626.   Returns the value of the \a{i}-th argument.  See argc().
  1627. */
  1628. const char* QNPInstance::argv(int i) const
  1629. {
  1630.     return pi->argv[i];
  1631. }
  1632.  
  1633. /*!
  1634.   Returns the mode of the plugin.
  1635. */
  1636. QNPInstance::InstanceMode QNPInstance::mode() const
  1637. {
  1638.     return (QNPInstance::InstanceMode)pi->fMode;
  1639. }
  1640.  
  1641. /*!
  1642.   Returns the value of the named arguments, or 0 if no argument
  1643.   with called \a name appears in the \c{<EMBED>} tag of this instance.
  1644.   If the argument appears, but has no value assigned, the empty
  1645.   string is returned.  In summary:
  1646.  
  1647.   \list
  1648.    \i \c{<EMBED ...>} -- arg("FOO") == 0
  1649.    \i \c{<EMBED FOO ...>} -- arg("FOO") == ""
  1650.    \i \c{<EMBED FOO=BAR ...>} -- arg("FOO") == "BAR"
  1651.   \endlist
  1652. */
  1653. const char* QNPInstance::arg(const char* name) const
  1654. {
  1655.     for (int i=0; i<pi->argc; i++) {
  1656.     // SGML: names are case insensitive
  1657.     if ( qstricmp( name, pi->argn[i] ) == 0 ) {
  1658.         if (pi->argv[i].isEmpty())
  1659.         return "";
  1660.         else
  1661.         return pi->argv[i];
  1662.     }
  1663.     }
  1664.     return 0;
  1665. }
  1666.  
  1667. /*!
  1668.   Returns the user agent (browser name) containing this instance.
  1669. */
  1670. const char* QNPInstance::userAgent() const
  1671. {
  1672.     return NPN_UserAgent(pi->npp);
  1673. }
  1674.  
  1675. /*!
  1676.     \preliminary
  1677.   This function is \e{not tested}.
  1678.  
  1679.   Requests the creation of a new data stream \e from the plug-in.
  1680.   The mime type and window are passed in \a mimetype and \a window. \a
  1681.   as_file holds the AsFileOnly flag.
  1682.   It is an interface to the NPN_NewStream
  1683.   function of the Netscape Plugin API.
  1684. */
  1685. QNPStream* QNPInstance::newStream(const char* mimetype, const char* window,
  1686.     bool as_file)
  1687. {
  1688.     NPStream* s=0;
  1689.     NPError err = NPN_NewStream(pi->npp, (char*)mimetype, window, &s);
  1690.     if (err != NPERR_NO_ERROR) return 0;
  1691.     return s ? new QNPStream(this, mimetype, s, as_file) : 0;
  1692. }
  1693.  
  1694. /*!
  1695.   Sets the status message in the browser containing this instance to
  1696.   \a msg.
  1697. */
  1698. void QNPInstance::status(const char* msg)
  1699. {
  1700.     NPN_Status(pi->npp, msg);
  1701. }
  1702.  
  1703.  
  1704. /*!
  1705.   Returns the Java object associated with the plug-in instance, an
  1706.   object of the
  1707.   \link QNPlugin::getJavaClass() plug-in's Java class\endlink,
  1708.   or 0 if the plug-in does not have a Java class, Java is disabled, or
  1709.   an error occurred.
  1710.  
  1711.   The return value is actually a \c{jref} we use \c{void*} so
  1712.   as to avoid burdening plugins which do not require Java.
  1713.  
  1714.   \sa QNPlugin::getJavaClass(), QNPlugin::getJavaEnv(), getJavaPeer()
  1715. */
  1716. void* QNPInstance::getJavaPeer() const
  1717. {
  1718.     return NPN_GetJavaPeer(pi->npp);
  1719. }
  1720.  
  1721.  
  1722. /*!
  1723.   \class QNPStream qnp.h
  1724.   \brief The QNPStream class provides a stream of data provided to a QNPInstance by the browser.
  1725.  
  1726.   \extension NSPlugin
  1727.  
  1728.   Note that this is neither a QTextStream nor a QDataStream.
  1729.  
  1730.   \sa QNPInstance::write(), QNPInstance::newStreamCreated()
  1731. */
  1732.  
  1733. /*!
  1734.   Creates a stream.  Plugins should not call this, but rather
  1735.   QNPInstance::newStream() if a stream is required.
  1736.  
  1737.     Takes a QNPInstance \a in, mime type \a mt, a pointer to an
  1738.     _NPStream \a st and a seekable flag \a se.
  1739. */
  1740. QNPStream::QNPStream(QNPInstance* in,const char* mt, _NPStream* st, bool se) :
  1741.     inst(in),
  1742.     stream(st),
  1743.     mtype(mt),
  1744.     seek(se)
  1745. {
  1746.     isokay = TRUE;
  1747.     iscomplete = FALSE;
  1748. }
  1749.  
  1750. /*!
  1751.   Destroys the stream.
  1752. */
  1753. QNPStream::~QNPStream()
  1754. {
  1755.     if (!qnps_no_call_back) {
  1756.     qnps_no_call_back++;
  1757.     NPN_DestroyStream(inst->pi->npp, stream, NPRES_USER_BREAK);
  1758.     qnps_no_call_back--;
  1759.     }
  1760. }
  1761.  
  1762. /*!
  1763.   \fn QNPInstance* QNPStream::instance()
  1764.  
  1765.   Returns the QNPInstance for which this stream was created.
  1766. */
  1767.  
  1768. /*!
  1769.   Returns the URL from which the stream was created.
  1770. */
  1771. const char* QNPStream::url() const
  1772. {
  1773.     return stream->url;
  1774. }
  1775.  
  1776. /*!
  1777.   Returns the length of the stream in bytes. Can be 0 for streams of
  1778.   unknown length.
  1779. */
  1780. uint QNPStream::end() const
  1781. {
  1782.     return stream->end;
  1783. }
  1784.  
  1785. /*!
  1786.   Returns the time when the source of the stream was last modified.
  1787. */
  1788. uint QNPStream::lastModified() const
  1789. {
  1790.     return stream->lastmodified;
  1791. }
  1792.  
  1793. /*!
  1794.   Returns the MIME type of the stream.
  1795. */
  1796. const char* QNPStream::type() const
  1797. {
  1798.     return mtype;
  1799. }
  1800.  
  1801. /*!
  1802.   Returns TRUE if the stream is seekable; otherwise returns FALSE.
  1803. */
  1804. bool QNPStream::seekable() const
  1805. {
  1806.     return seek;
  1807. }
  1808.  
  1809. /*!
  1810.   \internal
  1811. */
  1812. void QNPStream::setOkay(bool y)
  1813. {
  1814.     isokay = y;
  1815. }
  1816.  
  1817. /*!
  1818.   \internal
  1819. */
  1820. void QNPStream::setComplete(bool y)
  1821. {
  1822.     iscomplete = y;
  1823. }
  1824.  
  1825. /*!
  1826.   Returns TRUE if no errors have occurred on the stream; otherwise
  1827.   returns FALSE.
  1828. */
  1829. bool QNPStream::okay() const
  1830. {
  1831.     return isokay;
  1832. }
  1833.  
  1834. /*!
  1835.   Returns TRUE if the stream has received all the data from
  1836.   the source; otherwise returns FALSE.
  1837. */
  1838. bool QNPStream::complete() const
  1839. {
  1840.     return iscomplete;
  1841. }
  1842.  
  1843. /*!
  1844.   Requests the section of the stream, of \a length bytes from \a
  1845.   offset, be sent to the QNPInstance::write() function of the
  1846.   instance() of this stream.
  1847. */
  1848. void QNPStream::requestRead(int offset, uint length)
  1849. {
  1850.     NPByteRange range;
  1851.     range.offset = offset;
  1852.     range.length = length;
  1853.     range.next = 0; // ### Only one supported at this time
  1854.     NPN_RequestRead(stream, &range);
  1855. }
  1856.  
  1857. /*!
  1858.   Writes \a len bytes from \a buffer \e to the stream.
  1859. */
  1860. int QNPStream::write( int len, void* buffer )
  1861. {
  1862.     return NPN_Write(inst->pi->npp, stream, len, buffer);
  1863. }
  1864.  
  1865.  
  1866.  
  1867. /******************************************************************************
  1868.  * The plugin itself - only one ever exists, created by QNPlugin::create()
  1869.  *****************************************************************************/
  1870.  
  1871.  
  1872. /*!
  1873.   \class QNPlugin qnp.h
  1874.   \brief The QNPlugin class provides the plugin central factory.
  1875.  
  1876.   \extension NSPlugin
  1877.  
  1878.   This class is the heart of the plugin.  One instance of this object is
  1879.   created when the plugin is \e first needed, by calling
  1880.   QNPlugin::create(), which must be implemented in your plugin code to
  1881.   return some derived class of QNPlugin.  The one QNPlugin object creates
  1882.   all instances for a single running Web-browser process.
  1883.  
  1884.   Additionally, if Qt is linked to the plugin as
  1885.   a dynamic library, only one instance of QApplication will exist
  1886.   \e{across all plugins that have been made with Qt}.  So,
  1887.   your plugin should tread lightly on global settings - do not for
  1888.   example, use QApplication::setFont() - that will change the font in
  1889.   every widget of every Qt-based plugin currently loaded!
  1890. */
  1891.  
  1892. /*!
  1893.   \fn QNPlugin* QNPlugin::create()
  1894.  
  1895.   This must be implemented by your plugin code.  It should return a derived
  1896.   class of QNPlugin.
  1897. */
  1898.  
  1899. /*!
  1900.   Returns the plugin most recently returns by QNPlugin::create().
  1901. */
  1902. QNPlugin* QNPlugin::actual()
  1903. {
  1904.     return qNP;
  1905. }
  1906.  
  1907. /*!
  1908.   Creates a QNPlugin.  This may only be used by the constructor
  1909.   derived class returned by plugin's implementation of the
  1910.   QNPlugin::create() function.
  1911. */
  1912. QNPlugin::QNPlugin()
  1913. {
  1914.     // Encourage linker to include stuff.
  1915.     static void* a;
  1916.     a = (void*)NP_Initialize;
  1917.     a = (void*)NP_Shutdown;
  1918. }
  1919.  
  1920. /*!
  1921.   Destroys the QNPlugin.  This is called by the plugin binding code
  1922.   just before the plugin is about to be unloaded from memory.  If newWindow()
  1923.   has been called, a QApplication will still exist at this time, but will
  1924.   be deleted shortly after before the plugin is deleted.
  1925. */
  1926. QNPlugin::~QNPlugin()
  1927. {
  1928. }
  1929.  
  1930. /*!
  1931.   Populates \e *\a plugin_major and \e *\a plugin_minor with the
  1932.   version of the plugin API and populates \e *\a browser_major and \e
  1933.   *\a browser_minor with the version of the browser.
  1934. */
  1935. void QNPlugin::getVersionInfo(int& plugin_major, int& plugin_minor,
  1936.          int& browser_major, int& browser_minor)
  1937. {
  1938.     NPN_Version(&plugin_major, &plugin_minor, &browser_major, &browser_minor);
  1939. }
  1940.  
  1941. /*!
  1942.     \fn QNPInstance* QNPlugin::newInstance()
  1943.  
  1944.   Override this to return an appropriate derived class of QNPInstance.
  1945. */
  1946.  
  1947. /*!
  1948.     \fn const char* QNPlugin::getMIMEDescription() const
  1949.  
  1950.   Override this to return the MIME description of the data formats
  1951.   supported by your plugin.  The format of this string is shown
  1952.   by the following example:
  1953.  
  1954. \code
  1955.     const char* getMIMEDescription() const
  1956.     {
  1957.     return "image/x-png:png:PNG Image;"
  1958.            "image/png:png:PNG Image;"
  1959.            "image/x-portable-bitmap:pbm:PBM Image;"
  1960.            "image/x-portable-graymap:pgm:PGM Image;"
  1961.            "image/x-portable-pixmap:ppm:PPM Image;"
  1962.            "image/bmp:bmp:BMP Image;"
  1963.            "image/x-ms-bmp:bmp:BMP Image;"
  1964.            "image/x-xpixmap:xpm:XPM Image;"
  1965.            "image/xpm:xpm:XPM Image";
  1966.     }
  1967. \endcode
  1968. */
  1969.  
  1970. /*!
  1971.   \fn const char* QNPlugin::getPluginNameString() const
  1972.  
  1973.   Returns the plain-text name of the plugin.
  1974. */
  1975.  
  1976. /*!
  1977.   \fn const char* QNPlugin::getPluginDescriptionString() const
  1978.  
  1979.   Returns the plain-text description of the plugin.
  1980. */
  1981.  
  1982. /*!
  1983.   Override to return a reference to the Java class that represents
  1984.   the plugin.  The default returns 0, indicating no class.
  1985.  
  1986.   If you override this class, you must also override
  1987.   QNPlugin::unuseJavaClass().
  1988.  
  1989.   The return value is actually a \c{jref} we use \c{void*} so
  1990.   as to avoid burdening plugins which do not require Java.
  1991.  
  1992.   \sa getJavaEnv(), QNPInstance::getJavaPeer()
  1993. */
  1994. void* QNPlugin::getJavaClass()
  1995. {
  1996.     return NULL;
  1997. }
  1998.  
  1999. /*!
  2000.   This function is called when the plugin is shutting down,
  2001.   with jc set to the value returned earlier by getJavaClass().
  2002.   The function should \e unuse the Java class and return 0.
  2003. */
  2004. void QNPlugin::unuseJavaClass()
  2005. {
  2006.     qFatal("QNPlugin::unuseJavaClass() must overridden along with getJavaClass()");
  2007. }
  2008.  
  2009. /*!
  2010.   Returns a pointer to the Java execution environment, or 0 if
  2011.   Java is disabled or an error occurred.
  2012.  
  2013.   The return value is actually a \c{JRIEnv*} we use \c{void*} so
  2014.   as to avoid burdening plugins which do not require Java.
  2015.  
  2016.   \sa getJavaClass(), QNPInstance::getJavaPeer()
  2017. */
  2018. void* QNPlugin::getJavaEnv() const
  2019. {
  2020.     return NPN_GetJavaEnv();
  2021. }
  2022.